/*
 * FilePath     : \src\utils\datetimeUtil.ts
 * Author       : 苏军志
 * Date         : 2023-06-04 17:25
 * LastEditors  : 苏军志
 * LastEditTime : 2024-07-23 19:53
 * Description  : 时间相关方法
 * CodeIterationRecord:
 */
// 如果是日期，直接返回,如果是字符串或毫秒数，返回转换的日期；转换失败，返回原值
const toDate: any = (value: Date | string | number) => {
  let date: any = value;
  if (typeof value === "string" || typeof value === "number") {
    date = new Date(value);
    if (String(date) === "Invalid Date") {
      // 如果时间转换失败，
      date = new Date(`${formatDate(new Date(), "yyyy-MM-dd")} ${value}`);
    }
  }
  return date;
};
// 补零
const padLeftZero = (str: string, length: number) => {
  let newStr = str;
  let zero = "";
  if (length === 2) {
    zero = "00";
  }
  if (length === 3) {
    zero = "000";
  }
  newStr = (zero + str).substring(str.length);
  return newStr;
};

/**
 * 将日期转换为指定格式的字符串
 * @param value 日期
 * @param formatter 格式化格式
 * @returns
 */
const formatDate = (value: Date | string | number, formatter?: string) => {
  let date = toDate(value);
  let format = formatter;
  if (!format) {
    format = "yyyy-MM-dd hh:mm:ss";
  }
  const re = /(y+)/;
  if (re.test(format)) {
    const t = re.exec(format)?.[1] as string;
    format = format.replace(t, String(date.getFullYear()).substring(4 - t.length));
  }
  let o: any = {
    "M+": date.getMonth() + 1,
    "d+": date.getDate(),
    "h+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds(),
    "S+": date.getMilliseconds()
  };
  for (let k in o) {
    const regx = new RegExp(`(${k})`);
    if (regx.test(format)) {
      let str = o[k];
      const t = regx.exec(format)?.[1] as string;
      format = format.replace(t, t.length === 1 ? str : padLeftZero(String(str), t.length));
    }
  }
  return format;
};
/**
 * 日期，在原有日期基础上，增加day天数，默认增加1天
 * @param value 日期
 * @param day  增加day天数
 * @param formatter 格式化格式
 * @returns
 */
const addDate = (value: any, day?: number, formatter?: string) => {
  let newDay = day;
  let format = formatter;
  if (!newDay) {
    newDay = 1;
  }
  if (!format) {
    format = "yyyy-MM-dd hh:mm:ss";
  }
  const date = toDate(value);
  date.setDate(date.getDate() + newDay);
  return formatDate(date, format);
};

/**
 * 日期，在原有日期基础上，增加hours小时数，默认增加1小时
 * @param value
 * @param hours
 * @param formatter
 * @returns
 */
const addHours = (value: any, hours?: number, formatter?: string) => {
  let newHours = hours;
  let format = formatter;
  if (!newHours) {
    newHours = 1;
  }
  if (!format) {
    format = "yyyy-MM-dd hh:mm:ss";
  }
  let date = toDate(value);
  date = new Date(date.valueOf() + newHours * 60 * 60 * 1000); // 当前时间加上4小时
  return formatDate(date, format);
};
/**
 * 日期，在原有日期基础上，增加minutes分钟数，默认增加1分钟
 * @param value
 * @param minutes
 * @param formatter
 * @returns
 */
const addMinutes = (value: any, minutes?: number, formatter?: string) => {
  let newMinutes = minutes;
  let format = formatter;
  if (!newMinutes) {
    newMinutes = 1;
  }
  if (!format) {
    format = "yyyy-MM-dd hh:mm:ss";
  }
  let date = toDate(value);
  date = new Date(date.valueOf() + newMinutes * 60 * 1000);
  return formatDate(date, format);
};

/**
 * 获取当前年月日
 * @param formatter
 * @returns
 */
const getNowDate = (formatter?: string) => {
  let format = formatter;
  if (!format) {
    format = "yyyy-MM-dd";
  }
  return formatDate(new Date(), format);
};
/**
 * 获取当前时分秒
 * @param formatter
 * @returns
 */
const getNowTime = (formatter?: string) => {
  let format = formatter;
  if (!format) {
    format = "hh:mm:ss";
  }
  return formatDate(new Date(), format);
};
/**
 * 获取当前年月日时分秒
 * @param formatter
 * @returns
 */
const getNow = (formatter?: string) => {
  let format = formatter;
  if (!format) {
    format = "yyyy-MM-dd hh:mm:ss";
  }
  return formatDate(new Date(), format);
};
/**
 * 获取指定日期所在月的第一天
 * @param value 日期，不传获取当天
 * @returns
 */
const getMonthFirstDay = (value?: Date | string | number) => {
  const format = "yyyy-MM-dd";
  const date = value ? toDate(value) : new Date();
  const year = date.getFullYear();
  const month = date.getMonth();
  return formatDate(new Date(year, month, 1), format);
};
/**
 * 获取指定日期所在月的最后一天
 * @param value 日期，不传获取当天
 * @returns
 */
const getMonthLastDay = (value?: Date | string | number) => {
  const format = "yyyy-MM-dd";
  const date = value ? toDate(value) : new Date();
  const year = date.getFullYear();
  const month = date.getMonth();
  // day为0表示获取上一个月最后一天，所以month+1
  return formatDate(new Date(year, month + 1, 0), format);
};
//获取时间差
// startTime：开始时间
// endTime ：结束时间（默认为当前时间）
// timeType：开始时间和结束时间类型
//          date 日期类型（yyyy-MM-dd或yyyy-MM-dd hh:mm:ss）
//          time 时间类型（hh:mm:ss）
// returnType：时间差类型（默认为all）
//           D 相差天数
//           H 相差小时数
//           M 相差分钟数
//           S 相差秒数
//           all days + "天 " + hours + "小时 " + minutes + " 分钟" + seconds + " 秒";
// decimalPlace：返回值小数位数（默认整数）
let getTimeDifference = (startTime: any, endTime: any, timeType = "date", returnType = "all", decimalPlace = 0) => {
  if (!startTime) {
    return undefined;
  }
  //结束时间不传 默认为当前日期或当前时间
  if (!endTime) {
    if (timeType == "date") {
      endTime = getNow();
    }
    if (timeType == "time") {
      endTime = getNowTime("hh:mm:ss");
    }
  }
  //日期格式转换
  if (timeType == "date") {
    startTime = new Date(startTime);
    endTime = new Date(endTime);
  }
  //时间格式转换
  if (timeType == "time") {
    startTime = new Date(formatDate(new Date(), "yyyy-MM-dd") + " " + startTime);
    endTime = new Date(formatDate(new Date(), "yyyy-MM-dd") + " " + endTime);
  }
  //判断时间格式是否有误
  if (startTime == "Invalid Date" || endTime == "Invalid Date") {
    return undefined;
  }
  let dateDiff = endTime - startTime;
  //返回相差天数
  if (returnType == "D") {
    return (dateDiff / (24 * 3600 * 1000)).toFixed(decimalPlace);
  }
  //返回相差小时数
  if (returnType == "H") {
    return (dateDiff / (3600 * 1000)).toFixed(decimalPlace);
  }
  //返回相差分钟数
  if (returnType == "M") {
    return (dateDiff / (60 * 1000)).toFixed(decimalPlace);
  }
  //返回相差秒数
  if (returnType == "S") {
    return (dateDiff / 1000).toFixed(decimalPlace);
  }
  //返回相差所有
  if (returnType == "all") {
    let days = Math.floor(dateDiff / (24 * 3600 * 1000));
    //计算出小时数
    let leave1 = dateDiff % (24 * 3600 * 1000); //计算天数后剩余的毫秒数
    let hours = Math.floor(leave1 / (3600 * 1000));
    //计算相差分钟数
    let leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数
    let minutes = Math.floor(leave2 / (60 * 1000));
    //计算相差秒数
    let leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数
    let seconds = Math.round(leave3 / 1000);
    return days + "天" + hours + "小时" + minutes + "分钟" + seconds + "秒";
  }
  return undefined;
};
/**
 * @description: 计算日期午别相差天数
 * @param row
 * @return
 */
const getDateNoonDays = (row: Record<string, any>) => {
  // 行数据，开始日期，开始午别，结束日期，结束午别，任意一项为空，返回
  if (!row || !row.startDate || !row.startNoon || !row.endDate || !row.endNoon) {
    return;
  }
  let diffDays = getTimeDifference(row.startDate, row.endDate, "date", "D");
  if (row?.actualEndDate) {
    diffDays = getTimeDifference(row.startDate, row.actualEndDate, "date", "D");
  }
  // 相差天数加上开始时间那天
  let days = Number(diffDays) + 1;
  if (row.startNoon === "2") {
    days = days - 0.5;
  }
  if (row.endNoon === "1") {
    days = days - 0.5;
  }
  return days;
};
/**
 * description: 计算本月周数以及每周包含的号数
 * return {*}
 */
const getWeeksInMonth = () => {
  // 获取当前月份的第一天和最后一天
  const firstDayOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
  const lastDayOfMonth = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0);
  // js中getDay 0表示周日，1表示周一，以此类推
  const firstDayOfWeek = firstDayOfMonth.getDay();
  // 当前月份的总天数
  const totalDaysInMonth = lastDayOfMonth.getDate();
  // 当前月份的周数
  let totalWeeks = Math.ceil((totalDaysInMonth + firstDayOfWeek) / 7);
  // 返回容器
  const weeks = [];
  // 一天的毫秒数，用于换算时间戳
  let dayNumber = 24 * 60 * 60 * 1000;
  // 第一周
  let weekArr = [1, 2, 3, 4, 5, 6, 0];
  let index = weekArr.indexOf(firstDayOfWeek);
  let startOfWeek = new Date(firstDayOfMonth);
  let endOfWeek = new Date(firstDayOfMonth.getTime() + (6 - index) * dayNumber);
  weeks.push([startOfWeek, endOfWeek]);
  // 除却第一周这个月剩余天数
  let currentMouthDays = totalDaysInMonth - 7 - index;
  // 后续周
  let weekCount = 7;
  for (let i = 0; i < totalWeeks - 1; i++) {
    if (currentMouthDays - weekCount > 0) {
      // 一周满七天
      startOfWeek = new Date(endOfWeek.getTime() + dayNumber);
      endOfWeek = new Date(startOfWeek.getTime() + 6 * dayNumber);
      weeks.push([startOfWeek, endOfWeek]);
    } else if (currentMouthDays - weekCount < 0) {
      // 一周不满七天
      startOfWeek = new Date(endOfWeek.getTime() + dayNumber);
      endOfWeek = new Date(endOfWeek.getTime() + (totalDaysInMonth - startOfWeek.getDate() + 1) * dayNumber);
      weeks.push([startOfWeek, endOfWeek]);
    }
    weekCount += 7;
  }
  return weeks;
};
/**
 * @description: 获取周开始日期，每周从周一开始
 * @param value
 * @return
 */
const getWeekStartDate = (value?: Date | string | number) => {
  const format = "yyyy-MM-dd";
  const date = value ? toDate(value) : new Date();
  const year = date.getFullYear();
  const month = date.getMonth();
  //今天本周的第几天
  const nowDayOfWeek = date.getDay();
  return formatDate(new Date(year, month, date.getDate() - nowDayOfWeek + 1), format);
};
/**
 * @description: 获取周结束日期，每周从周一开始
 * @param value
 * @return
 */
const getWeekEndDate = (value?: Date | string | number) => {
  const format = "yyyy-MM-dd";
  const date = value ? toDate(value) : new Date();
  const year = date.getFullYear();
  const month = date.getMonth();
  //今天本周的第几天
  const nowDayOfWeek = date.getDay();
  return formatDate(new Date(year, month, date.getDate() + (7 - nowDayOfWeek)), format);
};
export default {
  toDate,
  formatDate,
  addDate,
  addHours,
  addMinutes,
  getNowDate,
  getNowTime,
  getNow,
  getMonthFirstDay,
  getMonthLastDay,
  getTimeDifference,
  getDateNoonDays,
  getWeeksInMonth,
  getWeekStartDate,
  getWeekEndDate
};
